home *** CD-ROM | disk | FTP | other *** search
- /******************************************************************************
- ** **
- ** Module: SR_PipelineSetup.c **
- ** **
- ** **
- ** Purpose: Sample Renderer setup routines, etc. **
- ** **
- ** **
- ** **
- ** Copyright (C) 1996 Apple Computer, Inc. All rights reserved. **
- ** **
- ** **
- *****************************************************************************/
- #include <assert.h>
-
- #include "QD3D.h"
- #include "QD3DMath.h"
- #include "QD3DCamera.h"
- #include "QD3DView.h"
- #include "QD3DTransform.h"
- #include "QD3DRenderer.h"
- #include "QD3DShader.h"
-
- #include "SR.h"
- #include "SR_Math.h"
-
- /******************************************************************************
- ** **
- ** Setup Routines **
- ** **
- *****************************************************************************/
-
- /*===========================================================================*\
- *
- * Routine: SR_ClipPlanesInDC()
- *
- * Comments: Compute clipping planes in device coordinates
- *
- \*===========================================================================*/
-
- static void SR_ClipPlanesInDC(
- TQ3Matrix4x4 *frustumToDC,
- float *clipPlanesInDC)
- {
- TQ3Point3D clipPlanesInFrustum[2];
- TQ3RationalPoint4D clipPlanesInDevCoords[2];
-
- assert(frustumToDC != NULL);
- assert(clipPlanesInDC != NULL);
-
- clipPlanesInFrustum[0].x = -1.0; /* xmin */
- clipPlanesInFrustum[0].y = -1.0; /* ymin */
- clipPlanesInFrustum[0].z = -1.0; /* zmin */
-
- clipPlanesInFrustum[1].x = 1.0; /* xmax */
- clipPlanesInFrustum[1].y = 1.0; /* ymax */
- clipPlanesInFrustum[1].z = 0.0; /* zmax */
-
- Q3Point3D_To4DTransformArray(
- (TQ3Point3D *)&clipPlanesInFrustum[0],
- frustumToDC,
- &clipPlanesInDevCoords[0],
- 2,
- sizeof(TQ3Point3D),
- sizeof(TQ3RationalPoint4D));
-
- /*
- * xmin, xmax
- */
- clipPlanesInDC[0] = FLOAT_ROUND_TO_LONG(clipPlanesInDevCoords[0].x);
- clipPlanesInDC[1] = FLOAT_ROUND_TO_LONG(clipPlanesInDevCoords[1].x - 1.0);
-
- /*
- * ymin, ymax
- */
- clipPlanesInDC[2] = FLOAT_ROUND_TO_LONG(clipPlanesInDevCoords[1].y);
- clipPlanesInDC[3] = FLOAT_ROUND_TO_LONG(clipPlanesInDevCoords[0].y - 1.0);
-
- /*
- * zmin, zmax
- */
- clipPlanesInDC[4] = clipPlanesInDevCoords[0].z;
- clipPlanesInDC[5] = clipPlanesInDevCoords[1].z;
- }
-
-
- /******************************************************************************
- ** **
- ** Attributes Update **
- ** **
- *****************************************************************************/
-
- /*===========================================================================*\
- *
- * Routine: SR_Update_DiffuseColor()
- *
- * Comments: Tracks changes to diffuse color state in the view
- *
- \*===========================================================================*/
-
- TQ3Status SR_Update_DiffuseColor(
- TQ3ViewObject view,
- TSRPrivate *srPrivate,
- TQ3ColorRGB *diffuseColor)
- {
- UNUSED(view);
-
- assert(view != NULL);
- assert(srPrivate != NULL);
- assert(diffuseColor != NULL);
-
- srPrivate->viewDiffuseColor = *diffuseColor;
-
- return (kQ3Success);
- }
-
-
- /*===========================================================================*\
- *
- * Routine: SR_Update_HighlightState()
- *
- * Comments: Tracks changes to highlight state in the view
- *
- \*===========================================================================*/
-
- TQ3Status SR_Update_HighlightState(
- TQ3ViewObject view,
- TSRPrivate *srPrivate,
- TQ3Boolean *highlightState)
- {
- UNUSED(view);
-
- assert(view != NULL);
- assert(srPrivate != NULL);
-
- srPrivate->viewHighlightState =
- (highlightState == NULL) ? kQ3False : *highlightState;
-
- return (kQ3Success);
- }
-
-
- /******************************************************************************
- ** **
- ** Styles **
- ** **
- *****************************************************************************/
-
- /*===========================================================================*\
- *
- * Routine: SR_Update_BackfacingStyle()
- *
- * Comments: Tracks changes to backfacing style state in the view
- *
- \*===========================================================================*/
-
- TQ3Status SR_Update_BackfacingStyle(
- TQ3ViewObject view,
- TSRPrivate *srPrivate,
- TQ3BackfacingStyle *backfacingStyle)
- {
- UNUSED(view);
-
- assert(view != NULL);
- assert(srPrivate != NULL);
- assert(backfacingStyle != NULL);
-
- srPrivate->backfacingStyle = *backfacingStyle;
-
- return (kQ3Success);
- }
-
-
- /*===========================================================================*\
- *
- * Routine: SR_Update_OrientationStyle()
- *
- * Comments: Tracks changes to orientation style state in the view
- *
- \*===========================================================================*/
-
- TQ3Status SR_Update_OrientationStyle(
- TQ3ViewObject view,
- TSRPrivate *srPrivate,
- TQ3OrientationStyle *orientationStyle)
- {
- UNUSED(view);
-
- assert(view != NULL);
- assert(srPrivate != NULL);
- assert(orientationStyle != NULL);
-
- srPrivate->orientationStyle = *orientationStyle;
-
- return (kQ3Success);
- }
-
-
- /*===========================================================================*\
- *
- * Routine: SR_Update_FillStyle()
- *
- * Comments: Tracks changes to fill style state in the view
- *
- \*===========================================================================*/
-
- TQ3Status SR_Update_FillStyle(
- TQ3ViewObject view,
- TSRPrivate *srPrivate,
- TQ3FillStyle *fillStyle)
- {
- UNUSED(view);
-
- assert(view != NULL);
- assert(srPrivate != NULL);
- assert(fillStyle != NULL);
-
- srPrivate->viewFillStyle = *fillStyle;
-
- return (kQ3Success);
- }
-
-
- /*===========================================================================*\
- *
- * Routine: SR_Update_HighlightStyle()
- *
- * Comments: Tracks changes to highlight style state in the view
- *
- \*===========================================================================*/
-
- TQ3Status SR_Update_HighlightStyle(
- TQ3ViewObject view,
- TSRPrivate *srPrivate,
- TQ3AttributeSet *highlightAttributeSet)
- {
- UNUSED(view);
-
- assert(view != NULL);
- assert(srPrivate != NULL);
-
- /*
- * Bump reference count on incoming attribute set, if any
- */
- if (*highlightAttributeSet != NULL) {
- Q3Shared_GetReference(*highlightAttributeSet);
- }
-
- /*
- * Get rid of existing highlight attribute set
- */
- if (srPrivate->viewHighlightAttributeSet != NULL) {
- Q3Object_Dispose(srPrivate->viewHighlightAttributeSet);
- }
-
- /*
- * Set the highlight attribute set
- */
- srPrivate->viewHighlightAttributeSet = *highlightAttributeSet;
-
- return (kQ3Success);
- }
-
-
- /*===========================================================================*\
- *
- * Routine: SR_UpdateNonInvertibleMatrix()
- *
- * Comments: Deal with noninvertible local-to-world matrices
- *
- \*===========================================================================*/
-
- static void SR_UpdateNonInvertibleMatrix(
- TSRPrivate *srPrivate,
- TQ3Boolean parallelProjection)
- {
- TQ3Matrix3x3 submatrix;
- long indexPtr[3];
- float rowInterchanges;
- long rank;
-
- /* Singular */
-
- /* Copy upper-left 3x3 submatrix to temporary array */
- submatrix.value[0][0] = srPrivate->transforms.localToWorld.value[0][0];
- submatrix.value[0][1] = srPrivate->transforms.localToWorld.value[0][1];
- submatrix.value[0][2] = srPrivate->transforms.localToWorld.value[0][2];
- submatrix.value[1][0] = srPrivate->transforms.localToWorld.value[1][0];
- submatrix.value[1][1] = srPrivate->transforms.localToWorld.value[1][1];
- submatrix.value[1][2] = srPrivate->transforms.localToWorld.value[1][2];
- submatrix.value[2][0] = srPrivate->transforms.localToWorld.value[2][0];
- submatrix.value[2][1] = srPrivate->transforms.localToWorld.value[2][1];
- submatrix.value[2][2] = srPrivate->transforms.localToWorld.value[2][2];
-
- /*
- * Decompose singular matrix into lower-triangular/upper-echelon form
- */
- SRMatrix_LUDecomposeSingular3x3(
- submatrix.value,
- indexPtr,
- &rowInterchanges,
- &rank);
-
- srPrivate->normalLocalToWorldRank = rank;
-
- if ((rank == 2) &&
- (SRMatrix_ComputeFlatLand(
- &srPrivate->transforms.localToWorld,
- &submatrix,
- parallelProjection,
- &srPrivate->eyeVectorInWorldCoords,
- &srPrivate->eyePointInWorldCoords,
- &srPrivate->eyeVectorInLocalCoords,
- &srPrivate->flatWorld) == kQ3Success)) {
- return;
- }
-
- /*
- * Fill in some arbitrary values if failure, or rank is 0, 1, or 3
- *
- * rank = 0
- *
- * All geometry is transformed to a single point. Lighting and
- * culling have no meaning so choose any arbitrary eye vector.
- * Renderers should render nothing, but let's set the values
- * to something in case they try to use them.
- *
- * rank = 0
- *
- * All geometry is transformed to a line. Lighting and
- * culling have no meaning so choose any arbitrary eye vector.
- * Renderers should render nothing, but let's set the values
- * to something in case they try to use them.
- *
- * rank = 1
- *
- * TODO:
- * The 4x4 matrix is singular, but the 3x3 upper-left submatrix
- * has rank 3 so the element[3][3] is zero. This means that
- * all geometry is transformed to infinity. This is useful concept
- * for mathematicians, but for now, let's do the wrong thing until
- * somebody reports a bug.
- */
-
- SRVector4D_Set(&srPrivate->eyeVectorInLocalCoords, 0.0, 0.0, 1.0, 0.0);
- Q3Vector3D_Set(&srPrivate->flatWorld.normal, 0.0, 0.0, 1.0);
- srPrivate->flatWorld.constant = 0.0;
- }
-
-
- /*===========================================================================*\
- *
- * Routine: SR_Update_LocalToWorldMatrix()
- *
- * Comments: Track changes to local-to-world transform
- *
- \*===========================================================================*/
-
- TQ3Status SR_Update_LocalToWorldMatrix(
- TQ3ViewObject view,
- TSRPrivate *srPrivate,
- TQ3Matrix4x4 *localToWorld)
- {
- assert(view != NULL);
- assert(srPrivate != NULL);
- assert(localToWorld != NULL);
-
- UNUSED(view);
-
- srPrivate->transforms.localToWorld = *localToWorld;
-
- srPrivate->transforms.dirtyLocalToWorld = kQ3True;
- srPrivate->transforms.validLocalToWorld = kQ3True;
-
- return (kQ3Success);
- }
-
-
- /*===========================================================================*\
- *
- * Routine: SR_Update_LocalToFrustumMatrix()
- *
- * Comments: Track changes to local-to-frustum transform
- *
- \*===========================================================================*/
-
- TQ3Status SR_Update_LocalToFrustumMatrix(
- TQ3ViewObject view,
- TSRPrivate *srPrivate,
- TQ3Matrix4x4 *localToFrustum)
- {
- assert(view != NULL);
- assert(srPrivate != NULL);
- assert(localToFrustum != NULL);
-
- UNUSED(view);
-
- srPrivate->transforms.localToFrustum = *localToFrustum;
-
- srPrivate->transforms.dirtyLocalToFrustum = kQ3True;
- srPrivate->transforms.validLocalToFrustum = kQ3True;
-
- return (kQ3Success);
- }
-
-
- /*===========================================================================*\
- *
- * Routine: SR_Update_WorldToFrustumMatrix()
- *
- * Comments: Track changes to world-to-frustum transform
- *
- \*===========================================================================*/
-
- TQ3Status SR_Update_WorldToFrustumMatrix(
- TQ3ViewObject view,
- TSRPrivate *srPrivate,
- TQ3Matrix4x4 *worldToFrustum)
- {
- assert(view != NULL);
- assert(srPrivate != NULL);
- assert(worldToFrustum != NULL);
-
- UNUSED(view);
-
- srPrivate->transforms.worldToFrustum = *worldToFrustum;
-
- srPrivate->transforms.dirtyWorldToFrustum = kQ3True;
- srPrivate->transforms.validWorldToFrustum = kQ3True;
-
- return (kQ3Success);
- }
-
-
- /*===========================================================================*\
- *
- * Routine: SR_SetupRegionDependentTransformations()
- *
- * Comments: Update the frustum-to-device coordinates transform
- *
- \*===========================================================================*/
-
- TQ3Status SR_SetupRegionDependentTransformations(
- TSRPrivate *srPrivate)
- {
- float frustumWindow[6] = { -1.0, 1.0, 1.0, -1.0, -1.0, 0.0 };
- float deviceViewport[6];
- TQ3Status status = kQ3Success;
-
- /*
- * The orientation of Frustum Coordinates is x right, y up, z toward.
- * The orientation of Device Coordinates is x right, y down, z toward.
- * The y axis is inverted in the mapping so the min and max values are
- * reversed in the Frustum boundaries.
- */
- {
- float tmp1, tmp2;
-
- /*
- * xmin
- */
- Q3XDrawRegion_GetDeviceOffsetX(srPrivate->drawRegion, &tmp1);
- deviceViewport[0] = tmp1;
-
- /*
- * xmax
- */
- Q3XDrawRegion_GetWindowScaleX(srPrivate->drawRegion, &tmp1);
- Q3XDrawRegion_GetDeviceOffsetX(srPrivate->drawRegion, &tmp2);
- deviceViewport[1] = tmp1 - 1.0 + tmp2;
-
- /*
- * ymin
- */
- Q3XDrawRegion_GetDeviceOffsetY(srPrivate->drawRegion, &tmp1);
- deviceViewport[2] = tmp1;
-
- /*
- * ymax
- */
- Q3XDrawRegion_GetWindowScaleY(srPrivate->drawRegion, &tmp1);
- Q3XDrawRegion_GetDeviceOffsetY(srPrivate->drawRegion, &tmp2);
- deviceViewport[3] = tmp1 - 1.0 + tmp2;
-
- /*
- * zmin, xmax
- */
- deviceViewport[4] = -1.0;
- deviceViewport[5] = 0.0;
- }
-
- srPrivate->transforms.frustumToDC.value[0][0]
- = (deviceViewport[1] - deviceViewport[0]) /
- (frustumWindow[1] - frustumWindow[0]);
- srPrivate->transforms.frustumToDC.value[1][1]
- = (deviceViewport[3] - deviceViewport[2]) /
- (frustumWindow[3] - frustumWindow[2]);
- srPrivate->transforms.frustumToDC.value[2][2]
- = (deviceViewport[5] - deviceViewport[4]) /
- (frustumWindow[5] - frustumWindow[4]);
- srPrivate->transforms.frustumToDC.value[3][0]
- = - srPrivate->transforms.frustumToDC.value[0][0] *
- frustumWindow[0] + deviceViewport[0];
- srPrivate->transforms.frustumToDC.value[3][1]
- = - srPrivate->transforms.frustumToDC.value[1][1] *
- frustumWindow[2] + deviceViewport[2];
- srPrivate->transforms.frustumToDC.value[3][2]
- = - srPrivate->transforms.frustumToDC.value[2][2] *
- frustumWindow[4] + deviceViewport[4];
-
- {
- TQ3Matrix4x4 *deviceTransform;
-
- if (Q3XDrawRegion_GetDeviceTransform(
- srPrivate->drawRegion,
- &deviceTransform) != NULL) {
- SR_ClipPlanesInDC(
- deviceTransform,
- &srPrivate->clipPlanesInDC[0]);
- } else {
- status = kQ3Failure;
- }
- }
-
- srPrivate->transforms.dirtyFrustumToDC = kQ3False;
- srPrivate->transforms.validFrustumToDC = kQ3True;
-
- return (status);
- }
-
-
- /*===========================================================================*\
- *
- * Routine: SR_SetupPipelineInitCamera()
- *
- * Comments: Set up intitial camera info.
- *
- \*===========================================================================*/
-
- void SR_SetupPipelineInitCamera(
- TSRPrivate *srPrivate,
- TQ3CameraObject camera)
- {
- assert(srPrivate != NULL);
- assert(camera != NULL);
-
- if (srPrivate->camera != NULL) {
- Q3Object_Dispose(srPrivate->camera);
- }
-
- srPrivate->camera = Q3Shared_GetReference(camera);
- srPrivate->cameraType = Q3Camera_GetType(camera);
- Q3Camera_GetPlacement(camera, &srPrivate->cameraPlacement);
-
- srPrivate->backfacingStyle = kQ3BackfacingStyleRemove;
- srPrivate->orientationStyle = kQ3OrientationStyleCounterClockwise;
-
- Q3Matrix4x4_SetIdentity(&srPrivate->transforms.localToWorld);
- srPrivate->transforms.dirtyLocalToWorld = kQ3False;
- srPrivate->transforms.validLocalToWorld = kQ3False;
-
- Q3Matrix4x4_SetIdentity(&srPrivate->transforms.worldToFrustum);
- srPrivate->transforms.dirtyWorldToFrustum = kQ3False;
- srPrivate->transforms.validWorldToFrustum = kQ3False;
-
- Q3Matrix4x4_SetIdentity(&srPrivate->transforms.localToFrustum);
- srPrivate->transforms.dirtyLocalToFrustum = kQ3False;
- srPrivate->transforms.validLocalToFrustum = kQ3False;
-
- Q3Matrix4x4_SetIdentity(&srPrivate->transforms.frustumToDC);
- srPrivate->transforms.dirtyFrustumToDC = kQ3False;
- srPrivate->transforms.validFrustumToDC = kQ3False;
-
- Q3Matrix4x4_SetIdentity(&srPrivate->transforms.localToDC);
- srPrivate->transforms.dirtyLocalToDC = kQ3False;
- srPrivate->transforms.validLocalToDC = kQ3False;
- }
-
-
- /*===========================================================================*\
- *
- * Routine: SR_SetupPipelineExit()
- *
- * Comments: Dispose of things to which SR has a reference.
- *
- \*===========================================================================*/
-
- void SR_SetupPipelineExit(
- TSRPrivate *srPrivate)
- {
- assert(srPrivate != NULL);
-
- /*
- * Dispose of highlight attribute set
- */
- if (srPrivate->viewHighlightAttributeSet != NULL) {
- Q3Object_Dispose(srPrivate->viewHighlightAttributeSet);
- srPrivate->viewHighlightAttributeSet = NULL;
- }
-
- /*
- * Dispose of camera
- */
- if (srPrivate->camera != NULL) {
- Q3Object_Dispose(srPrivate->camera);
- srPrivate->camera = NULL;
- }
- }
-
-
- /*===========================================================================*\
- *
- * Routine: SR_UpdatePipeline()
- *
- * Comments:
- *
- \*===========================================================================*/
-
- TQ3Status SR_UpdatePipeline(
- TSRPrivate *srPrivate)
- {
- TQ3Status status = kQ3Success;
-
- assert(srPrivate != NULL);
-
- /*
- * If no transforms have changed since the last primitive,
- * then simply return.
- */
- if (!(srPrivate->transforms.dirtyLocalToWorld ||
- srPrivate->transforms.dirtyLocalToFrustum ||
- srPrivate->transforms.dirtyWorldToFrustum ||
- srPrivate->transforms.dirtyFrustumToDC ||
- srPrivate->transforms.dirtyLocalToDC)) {
- return (kQ3Success);
- }
-
- /*
- * Create local-to-device-coordinates transform
- */
- Q3Matrix4x4_Multiply(
- &srPrivate->transforms.localToFrustum,
- &srPrivate->transforms.frustumToDC,
- &srPrivate->transforms.localToDC);
-
- /*
- *
- * Compute eye vector or point in local coordinates by
- * transforming the eye vector or point in world coordinates
- * back to local coordinates. If the local-to-world matrix
- * is singular and the upper-left 3x3 submatrix has rank 2,
- * compute the eye vector in local coordinates and the plane
- * equation of the transformed geometry in world coordinates
- * such that the vectors in both coordinate systems points
- * in the same hemisphere as the eye.
- *
- */
- if (srPrivate->cameraType == kQ3CameraTypeOrthographic) {
- TQ3Vector3D v;
- TSRVector4D eyeVectorWC;
- TQ3Matrix4x4 inverse;
-
- /* Orthographic projection */
-
- /* Calculate world eye vector from camera placement */
- Q3Point3D_Subtract(
- &srPrivate->cameraPlacement.cameraLocation,
- &srPrivate->cameraPlacement.pointOfInterest,
- &v);
- SRVector3D_To4D(&v, &eyeVectorWC);
- SRVector4D_Normalize(&eyeVectorWC, &srPrivate->eyeVectorInWorldCoords);
-
- if (Q3Matrix4x4_Invert(
- &srPrivate->transforms.localToWorld,
- &inverse) != NULL) {
- TSRVector4D eyeVectorLC;
- TQ3Matrix4x4 transpose;
-
- /* Nonsingular */
- Q3Matrix4x4_Transpose(
- &srPrivate->transforms.localToWorld,
- &transpose);
- SRVector4D_Transform(
- &eyeVectorWC,
- &transpose,
- &eyeVectorLC);
- SRVector4D_Normalize(
- &eyeVectorLC,
- &srPrivate->eyeVectorInLocalCoords);
-
- srPrivate->normalLocalToWorldRank = 3;
- } else {
- SR_UpdateNonInvertibleMatrix(srPrivate, kQ3True);
- }
- } else /* Non orthographic */ {
- TQ3Matrix4x4 inverse;
-
- /* Perspective projection */
-
- /* Get world eye location from camera placement */
- Q3Point3D_To4D(
- &srPrivate->cameraPlacement.cameraLocation,
- &srPrivate->eyePointInWorldCoords);
-
- if (Q3Matrix4x4_Invert(
- &srPrivate->transforms.localToWorld,
- &inverse) != NULL) {
- float wValue;
-
- /* Nonsingular */
- Q3RationalPoint4D_Transform(
- &srPrivate->eyePointInWorldCoords,
- &inverse,
- &srPrivate->eyePointInLocalCoords);
-
- wValue = 1.0 / srPrivate->eyePointInLocalCoords.w;
-
- srPrivate->eyePointInLocalCoords.x *= wValue;
- srPrivate->eyePointInLocalCoords.y *= wValue;
- srPrivate->eyePointInLocalCoords.z *= wValue;
- srPrivate->eyePointInLocalCoords.w = 1.0;
-
- srPrivate->normalLocalToWorldRank = 3;
- } else {
- SR_UpdateNonInvertibleMatrix(srPrivate, kQ3False);
- }
- }
-
- /*
- * Set the states of the transforms to "clean"
- */
- srPrivate->transforms.dirtyLocalToWorld = kQ3False;
- srPrivate->transforms.dirtyLocalToFrustum = kQ3False;
- srPrivate->transforms.dirtyWorldToFrustum = kQ3False;
- srPrivate->transforms.dirtyFrustumToDC = kQ3False;
- srPrivate->transforms.dirtyLocalToDC = kQ3False;
-
- /*
- * Set validity state
- */
- srPrivate->transforms.validLocalToDC = kQ3True;
-
- return (kQ3Success);
- }
-